package com.joshua.spring.gateway.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.joshua.spring.gateway.constant.SymbolConstants;
import com.joshua.spring.gateway.entity.bo.RouteDefinitionGroup;
import com.joshua.spring.gateway.entity.dto.RouteDefinitionGroupOptDTO;
import com.joshua.spring.gateway.entity.eum.OptTypeEnum;
import com.joshua.spring.gateway.entity.form.GatewayForm;
import com.joshua.spring.entity.vo.GlobalResponse;
import com.joshua.spring.gateway.repo.RedisRouteDefinitionRepository;
import com.joshua.spring.gateway.service.DynamicRouteService;
import com.joshua.spring.util.KeyUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import java.util.Collection;

import static com.joshua.spring.constants.UrlConstants.LB_URL_PREFIX;


/**
 * projectName dragon-cloud
 * package com.joshua.spring.gateway.controller
 * classname  GatewayController
 * <p>
 * description 动态网关路由
 * </p>
 *
 * @author <a href="mailto:joshualwork@163.com">joshua_liu</a>
 * @date 2020/8/22 10:19
 */
@RestController
@RequestMapping("dragon-gty")
public class GatewayV2Controller implements ApplicationEventPublisherAware {
    @Autowired
    private DynamicRouteService dynamicRouteService;

    @Autowired
    private RedisRouteDefinitionRepository redisRouteDefinitionRepository;
    private ApplicationEventPublisher eventPublisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.eventPublisher = applicationEventPublisher;
    }

    /**
     * description: 推送信息到redis
     *
     * @param routeDefinitionGroup 推送数据对象
     * @throws Exception 推送失败抛出异常
     * @author <a href="mailto:joshualwork@163.com">joshua_liu</a>
     * @date 2020/8/22 10:38
     */
    public void persistenceRouteDefinition(RouteDefinitionGroup routeDefinitionGroup, OptTypeEnum optType) throws Exception {
        RouteDefinitionGroupOptDTO dto = new RouteDefinitionGroupOptDTO();
        dto.setOptType(optType);
        dto.setRouteDefinitionGroup(routeDefinitionGroup);
        eventPublisher.publishEvent(dto);
    }

    @PostMapping
    @SentinelResource("gateway-add")
    public GlobalResponse addGatewayInfo(@RequestBody GatewayForm form) throws Exception {
        String routeId = KeyUtils.defaultKeyGen();
        RouteDefinitionGroup routeDefinitionGroup = routeDefinitionGroupInit(routeId, form);
        dynamicRouteService.add(routeDefinitionGroup.getRouteDefinition());
        persistenceRouteDefinition(routeDefinitionGroup, OptTypeEnum.I);
        return GlobalResponse.buildSuccess();
    }

    @PutMapping("id/{routeId}")
    public GlobalResponse updateGatewayInfo(@RequestBody GatewayForm form, @PathVariable String routeId) throws Exception {
        RouteDefinitionGroup routeDefinitionGroup = routeDefinitionGroupInit(routeId, form);
        dynamicRouteService.update(routeDefinitionGroup.getRouteDefinition());
        persistenceRouteDefinition(routeDefinitionGroup, OptTypeEnum.U);
        return GlobalResponse.buildSuccess();
    }

    @DeleteMapping("id/{routeId}")
    public GlobalResponse delGatewayInfo(@PathVariable String routeId) throws Exception {
        dynamicRouteService.delete(routeId);
        persistenceRouteDefinition(redisRouteDefinitionRepository.ROUTE_DEFINITION_GROUP.get(routeId), OptTypeEnum.D);
        return GlobalResponse.buildSuccess();
    }

    @GetMapping
    public GlobalResponse listGatewayInfo() {
        Collection<RouteDefinitionGroup> list = redisRouteDefinitionRepository.ROUTE_DEFINITION_GROUP.values();
        return GlobalResponse.buildSuccess(list);
    }

    private RouteDefinitionGroup routeDefinitionGroupInit(String routeId, GatewayForm form) {
        String applicationCode = form.getUri().replace(LB_URL_PREFIX, SymbolConstants.EMPTY_STR);
        RouteDefinitionGroup routeDefinitionGroup = new RouteDefinitionGroup();
        routeDefinitionGroup.setRouteId(routeId);
        routeDefinitionGroup.setApplicationCode(applicationCode);
        BeanUtils.copyProperties(form, routeDefinitionGroup);
        RouteDefinition routeDefinition = new RouteDefinition();
        BeanUtils.copyProperties(form, routeDefinition);
        URI uri = URI.create(form.getUri());
        routeDefinition.setUri(uri);
        routeDefinition.setId(routeId);
        routeDefinitionGroup.setRouteDefinition(routeDefinition);
        return routeDefinitionGroup;
    }
}
